package logic

import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"errors"
	"image/png"
	"time"
	"yuanxin-admin/internal/common"
	"yuanxin-admin/internal/dto"
	"yuanxin-admin/internal/model"
	"yuanxin-admin/internal/repository"
	"yuanxin-admin/internal/service"
	"yuanxin-admin/internal/utils"
	"yuanxin-admin/internal/vo"

	"gitee.com/botaoshow/yuanxin/web/common/database"
	"gitee.com/botaoshow/yuanxin/web/common/redis"
	"gitee.com/botaoshow/yuanxin/web/utils/pages"
	"gitee.com/botaoshow/yuanxin/web/utils/strs"
	"gitee.com/botaoshow/yuanxin/web/utils/tokens"
	"github.com/google/uuid"
	"github.com/jinzhu/copier"
)

func NewSysUserService() service.ISysUserService {
	return &SysUserServiceImpl{}
}

type SysUserServiceImpl struct {
}

func (s SysUserServiceImpl) ImageCaptcha(c context.Context) (captchaKey string, captchaImage string, error error) {
	code, img, err := utils.DrawCaptcha()
	if err != nil {
		return "", "", err
	}
	// 将图片编码为base64
	var buf bytes.Buffer
	if err := png.Encode(&buf, img); err != nil {
		return "", "", err
	}

	// 生成UUID作为key
	key, err := uuid.NewUUID()
	if err != nil {
		return "", "", err
	}

	// 存储验证码到redis，2分钟过期
	redis.Rdb.Set(c, "captcha:"+key.String(), code, time.Minute*2)

	// 返回base64图片和key
	return key.String(), "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes()), nil
}

func (s SysUserServiceImpl) Login(c context.Context, loginDto dto.SysUserLoginDto) (interface{}, error) {
	username := loginDto.Username
	password := loginDto.Password
	password, err := common.DePsw(password)
	if err != nil {
		return nil, errors.New("密码解密失败" + err.Error())
	}
	//过期时间为120分钟
	timeOut := int32(120)
	user := repository.SysUser
	if sysUser, err := user.WithContext(c).
		Where(user.Username.Eq(username)).First(); err != nil {
		return nil, errors.New("用户不存在")
	} else {
		var userInfoVO *vo.UserInfoVO
		if sysUser == nil {
			err = errors.New("用户不存在")
		} else if password != sysUser.Password {
			err = errors.New("用户名或密码错误")
		} else if sysUser.Status != "0" {
			err = errors.New("用户已禁用")
		} else {
			var roles []string
			err := repository.SysUserRole.WithContext(c).
				Select(repository.SysRole.RoleCode).Distinct(repository.SysRole.RoleCode).
				LeftJoin(repository.SysRole, repository.SysRole.ID.EqCol(repository.SysUserRole.RoleID)).
				Where(repository.SysUserRole.UserID.Eq(sysUser.ID)).Scan(&roles)
			if err != nil {
				return nil, err
			}
			sysUser.Password = "***"
			jwtToken, shortToken, _ := tokens.GenToken2(sysUser.ID, sysUser)

			userInfoVO = &vo.UserInfoVO{
				UserId:   sysUser.ID,
				Username: sysUser.Username,
				Nickname: sysUser.Nickname,
				Avatar:   *sysUser.Avatar,
				Email:    *sysUser.Email,
				Phone:    *sysUser.Phone,
				Sex:      sysUser.Sex,
				Status:   sysUser.Status,
				Token:    jwtToken,
				Roles:    roles,
			}

			var sessionDTO = &dto.LoginUserSessionDTO{
				UserId:        sysUser.ID,
				Username:      sysUser.Username,
				Token:         jwtToken,
				LoginTime:     time.Now().Unix(),
				ExpireTime:    time.Now().Unix() + int64(timeOut*60),
				Ipaddr:        "127.0.0.1",
				LoginLocation: "中国",
				Browser:       "Chrome",
				Os:            "Windows",
				Roles:         roles,
			}
			//缓存token
			marshal, err := json.Marshal(sessionDTO)
			redis.Rdb.Set(c, "tokens:"+shortToken, marshal, time.Minute*time.Duration(timeOut))
		}
		return userInfoVO, err
	}
}

func (s SysUserServiceImpl) Logout(c context.Context, token string) error {
	redis.Rdb.Del(c, "tokens:"+token)
	return nil
}

func (s SysUserServiceImpl) ChangePassword(c context.Context, userId, oldPassword, newPassword string) (bool, error) {
	user := repository.SysUser
	resultInfo, err := user.WithContext(c).
		Where(user.ID.Eq(userId)).
		Where(user.Password.Eq(oldPassword)).
		Update(user.Password, newPassword)
	return resultInfo.RowsAffected > 0, err

}

func (s SysUserServiceImpl) UpdateStatus(c context.Context, id string, status string) (bool, error) {
	user := repository.SysUser
	resultInfo, err := user.WithContext(c).
		Where(user.ID.Eq(id)).
		Update(user.Status, status)
	return resultInfo.RowsAffected > 0, err
}

func (s SysUserServiceImpl) QueryList(c context.Context, d *dto.SysUserQueryDTO) (*pages.Page[vo.SysUserVO], error) {
	o, l := pages.GetOffsetAndLimit(d.PageNum, d.PageSize)

	q := repository.SysUser.WithContext(c)
	q = q.Select(repository.SysUser.ALL, repository.SysDept.ID.As("deptId"),
		repository.SysDept.DeptName).
		LeftJoin(repository.SysDept, repository.SysDept.ID.EqCol(repository.SysUser.DeptID))

	if d.Username != "" {
		q = q.Where(repository.SysUser.Username.Like("%" + d.Username + "%"))
	}
	if d.Nickname != "" {
		q = q.Where(repository.SysUser.Nickname.Like("%" + d.Nickname + "%"))
	}
	if d.Phone != "" {
		q = q.Where(repository.SysUser.Phone.Like("%" + d.Phone + "%"))
	}
	if d.Email != "" {
		q = q.Where(repository.SysUser.Email.Like("%" + d.Email + "%"))
	}
	if d.Status != "" {
		q = q.Where(repository.SysUser.Status.Eq(d.Status))
	}
	if d.DeptId != "" {
		q = q.Where(repository.SysUser.DeptID.Eq(d.DeptId))
	}
	if len(d.DeptIds) > 0 {
		q = q.Where(repository.SysUser.DeptID.In(d.DeptIds...))
	}
	var page []*vo.SysUserVO
	count, err := q.ScanByPage(&page, o, l)
	if err != nil {
		return nil, err
	}
	// 手动填充角色数据
	for _, userVo := range page {
		var roles []*model.SysRole
		_ = repository.SysUserRole.WithContext(c).
			Select(repository.SysRole.ALL).
			LeftJoin(repository.SysRole, repository.SysRole.ID.EqCol(repository.SysUserRole.RoleID)).
			Where(repository.SysUserRole.UserID.Eq(userVo.ID)).Scan(&roles)
		userVo.Roles = roles
	}
	newPage := pages.NewPage[vo.SysUserVO](page, count, d.PageNum, d.PageSize)
	return newPage, nil

}

func (s SysUserServiceImpl) Save(c context.Context, d *dto.SysUserDTO) (bool, error) {
	sysUser := model.SysUser{}
	// 复制属性
	err := copier.Copy(&sysUser, d)
	if err != nil {
		return false, err
	}
	sysUser.ID = strs.GetUUIDWithoutDashUpper()
	sysUser.Password = d.Username
	now := time.Now()
	sysUser.CreatedAt = &now
	// 检测username唯一
	count, err := repository.SysUser.WithContext(c).Where(repository.SysUser.Username.Eq(sysUser.Username)).
		Count()
	if err != nil {
		return false, err
	}
	if count > 0 {
		return false, errors.New("用户名[" + sysUser.Username + "]已存在")
	}

	q := repository.Use(database.Db)
	err = q.Transaction(func(tx *repository.Query) error {
		err = tx.SysUser.WithContext(c).Create(&sysUser)
		if err != nil {
			return err
		}
		roleList, err := tx.SysRole.WithContext(c).Find()
		if err != nil {
			return err
		}
		id := sysUser.ID
		var sysUserRoles []*model.SysUserRole

		for _, role := range d.Roles {
			sysUserRole := model.SysUserRole{}
			sysUserRole.ID = strs.GetUUIDWithoutDashUpper()
			sysUserRole.UserID = id
			// 查找匹配的roleId
			roleId := ""
			for _, sysRole := range roleList {
				if sysRole.RoleCode == role {
					roleId = sysRole.ID
					break
				}
			}
			sysUserRole.RoleID = roleId
			sysUserRoles = append(sysUserRoles, &sysUserRole)
		}
		if len(sysUserRoles) > 0 {
			err = tx.SysUserRole.WithContext(c).CreateInBatches(sysUserRoles, 100)
			if err != nil {
				return err
			}
		}
		return nil
	})

	if err != nil {
		return false, err
	}
	return true, nil
}

func (s SysUserServiceImpl) Update(c context.Context, id string, d *dto.SysUserDTO) (bool, error) {
	sysUser := model.SysUser{}
	sysUser.ID = id
	// 复制属性
	err := copier.Copy(&sysUser, d)
	if err != nil {
		return false, err
	}
	sysUser.Username = "" // 设置为null
	now := time.Now()
	sysUser.UpdatedAt = &now

	q := repository.Use(database.Db)
	err = q.Transaction(func(tx *repository.Query) error {
		updates, err := tx.SysUser.WithContext(c).Where(tx.SysUser.ID.Eq(id)).Updates(sysUser)
		if err != nil {
			return err
		}
		if updates.RowsAffected > 0 {
			// 删除用户角色关联
			_, _ = tx.SysUserRole.WithContext(c).Where(tx.SysUserRole.UserID.Eq(id)).Delete()

			// 获取所有角色列表
			roleList, err := tx.SysRole.WithContext(c).Find()
			if err != nil {
				return err
			}
			var sysUserRoles []*model.SysUserRole

			// 为用户重新分配角色
			for _, role := range d.Roles {
				sysUserRole := model.SysUserRole{}
				sysUserRole.ID = strs.GetUUIDWithoutDashUpper()
				sysUserRole.UserID = id

				// 查找匹配的角色ID
				roleId := ""
				for _, sysRole := range roleList {
					if sysRole.RoleCode == role {
						roleId = sysRole.ID
						break
					}
				}
				sysUserRole.RoleID = roleId
				sysUserRoles = append(sysUserRoles, &sysUserRole)
			}

			// 批量保存用户角色关联
			if len(sysUserRoles) > 0 {
				err = tx.SysUserRole.WithContext(c).CreateInBatches(sysUserRoles, 100)
				if err != nil {
					return err
				}
			}
		}
		return nil
	})

	if err != nil {
		return false, err
	}

	return true, nil
}

func (s SysUserServiceImpl) Delete(c context.Context, id string) (bool, error) {
	user := repository.SysUser
	resultInfo, err := user.WithContext(c).
		Where(user.ID.Eq(id)).
		Delete()
	return resultInfo.RowsAffected > 0, err
}
